﻿using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Math.EC;
using System.Text;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Share.Services;

public class GMCipherService(ILogger<GMCipherService> logger, IOptions<ApiSetting> options) : ICipherService
{
    private readonly ApiSetting setting = options.Value;
    //private readonly string publicKey = options.Value.PublicKey;
    //private readonly string privateKey = options.Value.PrivateKey;
    /// <summary>
    /// 公钥加密
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public byte[] Encrypt(byte[] data)
    {
        ArgumentNullException.ThrowIfNull(data);
        ArgumentNullException.ThrowIfNull(setting.PublicKey);

        X9ECParameters sm2Params = GMNamedCurves.GetByName("sm2p256v1");
        ECPoint q = sm2Params.Curve.DecodePoint(Hex.Decode(setting.PublicKey));
        ECDomainParameters domainParameters = new ECDomainParameters(sm2Params.Curve, sm2Params.G, sm2Params.N, sm2Params.H);
        AsymmetricKeyParameter keyParameter = new ECPublicKeyParameters(q, domainParameters);
        SM2Engine engine = new SM2Engine();
        engine.Init(true, new ParametersWithRandom(keyParameter, new SecureRandom()));
        byte[] encryptedData = engine.ProcessBlock(data, 0, data.Length);
        return encryptedData;
    }

    /// <summary>
    /// 私钥签名
    /// </summary>
    /// <param name="plaintext"></param>
    /// <returns></returns>
    public string Sign(string plaintext)
    {
        try
        {
            // 将16进制私钥转换为字节数组
            byte[] privateKeyBytes = Hex.Decode(setting.PrivateKey);

            // 创建ECPrivateKeyParameters
            BigInteger d = new BigInteger(1, privateKeyBytes);
            X9ECParameters ecParams = ECNamedCurveTable.GetByName("sm2p256v1");
            ECDomainParameters domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());
            ECPrivateKeyParameters privateKeyParam = new ECPrivateKeyParameters(d, domainParams);

            // 初始化签名器
            ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
            signer.Init(true, privateKeyParam);

            // 转换数据为字节数组并签名
            byte[] dataBytes = Encoding.UTF8.GetBytes(plaintext);
            signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
            byte[] signature = signer.GenerateSignature();

            // 将签名结果转换为16进制字符串以便显示或传输
            //return BitConverter.ToString(signature).Replace("-", "").ToLower();                    
            return Convert.ToBase64String(signature);

        }
        catch (Exception ex)
        {
            logger.LogError("签名过程中发生错误: " + ex.Message);
        }
        return "";
    }

    public bool Verify(string plaintext, string sign)
    {
        try
        {
            logger.LogDebug(plaintext);
            logger.LogDebug(sign);

            // 将16进制公钥转换为字节数组
            byte[] publicKeyBytes = Hex.Decode(setting.GatewayPublicKey);

            // 创建ECPublicKeyParameters
            X9ECParameters ecParams = GMNamedCurves.GetByName("sm2p256v1");
            ECPoint q = ecParams.Curve.DecodePoint(publicKeyBytes);
            ECDomainParameters domainParams = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H);
            ECPublicKeyParameters publicKeyParam = new ECPublicKeyParameters(q, domainParams);

            // 初始化签名器
            ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
            signer.Init(false, publicKeyParam);

            // 转换数据为字节数组并验证签名
            byte[] dataBytes = Encoding.UTF8.GetBytes(plaintext);
            signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
            byte[] signature = Convert.FromBase64String(sign);
            return signer.VerifySignature(signature);
        }
        catch (Exception ex)
        {
            logger.LogError("验签过程中发生错误: " + ex.Message);
        }
        return false;
    }

    #region 密钥生成
    public (string, string) KeyGen()
    {
        X9ECParameters x9 = GMNamedCurves.GetByName("SM2P256V1");
        ECKeyPairGenerator eCKeyPairGenerator = new();
        eCKeyPairGenerator.Init(new ECKeyGenerationParameters(new ECDomainParameters(x9), new SecureRandom()));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = eCKeyPairGenerator.GenerateKeyPair();
        var publicKey = ((ECPublicKeyParameters)asymmetricCipherKeyPair.Public).Q.GetEncoded(compressed: false);
        var privateKey = ((ECPrivateKeyParameters)asymmetricCipherKeyPair.Private).D.ToByteArray();
        //return new Dictionary<string, string>
        //{
        //    { "publicKey", Hex.ToHexString(publicKey) },
        //    { "privateKey", Hex.ToHexString(privateKey) }
        //};
        return (Hex.ToHexString(publicKey), Hex.ToHexString(privateKey));
    }
    #endregion

    #region SM3摘要
    public byte[] ComputeHash(string message)
    {
        var digest = new SM3Digest();
        var bytes = Encoding.UTF8.GetBytes(message);
        digest.BlockUpdate(bytes, 0, bytes.Length);
        byte[] result = new byte[digest.GetDigestSize()];
        digest.DoFinal(result, 0);
        return result;
    }
    #endregion
}